package top.infopub.zookeeper;


import org.apache.commons.lang3.StringUtils;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import top.infopub.zookeeper.confclient.ContextUtils;


/**
 * 初始化zookeeper客户端
 * @author Awoke
 * @version 2018年9月14日
 * @see ZookeeperFactoryBean
 * @since
 */
public class ZookeeperFactoryBean implements FactoryBean<CuratorFramework>, InitializingBean, DisposableBean {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private CuratorFramework zkClient;

    /**
     * zk-conf basePath
     */
    private String zkConfBase;

    /**
     * 当前项目名称
     */
    private String projectName;

    private String zkConnectionString;

    // 设置ZK链接串
    public void setZkConnectionString(String zkConnectionString) {
        this.zkConnectionString = zkConnectionString;
    }

    @Override
    public CuratorFramework getObject() {
        return zkClient;
    }

    @Override
    public Class<?> getObjectType() {
        return CuratorFramework.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public void destroy()
        throws Exception {
        zkClient.close();
        logger.info("zkClient closed...");
        // 解决warn Could not load org.apache.zookeeper.server.ZooTrace
        // 参见：https://cloud.tencent.com/developer/article/1120284
        // 等待zookeeper的相关线程完全退出 by Awoke
        synchronized (zkClient) {
            zkClient.wait(500L);
        }
    }

    // 创建ZK链接
    @Override
    public void afterPropertiesSet() {
        // 1000 是重试间隔时间基数，3 是重试次数
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        zkClient = createWithOptions(zkConnectionString, retryPolicy, 2000, 10000);
        zkClient.start();
        logger.info("zkClient start successfully...");
    }

    /**
     * 通过自定义参数创建
     */
    public CuratorFramework createWithOptions(String connectionString, RetryPolicy retryPolicy,
                                              int connectionTimeoutMs, int sessionTimeoutMs) {
        /** 不使用密码连接   **/
        return CuratorFrameworkFactory.builder().connectString(connectionString).retryPolicy(
            retryPolicy).connectionTimeoutMs(connectionTimeoutMs).sessionTimeoutMs(
            sessionTimeoutMs).build();
    }

    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
        ContextUtils.PROJECT_NAME = projectName;
    }

    public String getZkConfBase() {
        return zkConfBase;
    }

    public void setZkConfBase(String zkConfBase) {
        this.zkConfBase = zkConfBase;
        if (StringUtils.isNotBlank(zkConfBase)) {
            ZookeeperConst.CONFIG_PATH = "/infopub/" + zkConfBase + "/conf/";
            logger.info("ZK_CONFIG_PATH change to: " + ZookeeperConst.CONFIG_PATH);
        }
    }

}